package org.wmq.protobuf;

import com.google.protobuf.InvalidProtocolBufferException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

/**
 * Protobuf转换工具类
 * 提供完整的Java对象与Protobuf格式之间的序列化与反序列化功能
 */
public class ProtobufConverter {
    private static final Logger logger = Logger.getLogger(ProtobufConverter.class.getName());
    private static final int BUFFER_SIZE = 4096;

    /**
     * 将Java的Message对象转换为Protobuf的字节数组
     * @param message Java的Message对象
     * @return 编码后的Protobuf字节数组
     * @throws IllegalArgumentException 如果message为null
     */
    public static byte[] encodeMessage(Message message) {
        if (message == null) {
            throw new IllegalArgumentException("Message对象不能为空");
        }
        
        try {
            // 创建Protobuf的Builder对象
            MessageProto.Message.Builder builder = MessageProto.Message.newBuilder();
            
            // 设置各个字段的值
            if (message.getName() != null) {
                builder.setName(message.getName());
            }
            if (message.getId() != null) {
                builder.setId(message.getId());
            }
            if (message.getClazz() != null) {
                builder.setClazz(message.getClazz());
            }
            builder.setCompulsory(message.getCompulsory() != null && message.getCompulsory());
            
            // 构建并序列化为字节数组
            MessageProto.Message protoMessage = builder.build();
            byte[] result = protoMessage.toByteArray();
            
            logger.fine("Message对象序列化成功，字节数: " + result.length);
            return result;
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Message对象序列化失败", e);
            throw new RuntimeException("序列化Message对象失败: " + e.getMessage(), e);
        }
    }

    /**
     * 将Java的Message对象转换为Protobuf的字节数组，并进行压缩
     * @param message Java的Message对象
     * @param compressionLevel 压缩级别（0-9，0表示无压缩，9表示最高压缩）
     * @return 编码并压缩后的Protobuf字节数组
     * @throws IllegalArgumentException 如果参数无效
     */
    public static byte[] encodeMessageWithCompression(Message message, int compressionLevel) {
        if (message == null) {
            throw new IllegalArgumentException("Message对象不能为空");
        }
        if (compressionLevel < 0 || compressionLevel > 9) {
            throw new IllegalArgumentException("压缩级别必须在0-9之间");
        }
        
        try {
            byte[] protobufBytes = encodeMessage(message);
            
            if (compressionLevel == 0) {
                return protobufBytes;
            }
            
            // 压缩数据
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Deflater deflater = new Deflater(compressionLevel);
            DeflaterOutputStream dos = new DeflaterOutputStream(baos, deflater);
            dos.write(protobufBytes);
            dos.close();
            
            byte[] compressedBytes = baos.toByteArray();
            logger.fine("Message对象序列化并压缩成功，原始大小: " + protobufBytes.length + ", 压缩后大小: " + compressedBytes.length);
            return compressedBytes;
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Message对象序列化并压缩失败", e);
            throw new RuntimeException("序列化并压缩Message对象失败: " + e.getMessage(), e);
        }
    }

    /**
     * 将Protobuf字节数组解析为Java的Message对象
     * @param bytes Protobuf字节数组
     * @return 解析后的Java Message对象
     * @throws IOException 当解析失败时抛出
     * @throws IllegalArgumentException 如果bytes为null或空
     */
    public static Message decodeMessage(byte[] bytes) throws IOException {
        if (bytes == null || bytes.length == 0) {
            throw new IllegalArgumentException("字节数组不能为空");
        }
        
        try {
            // 解析字节数组为Protobuf的Message对象
            MessageProto.Message protoMessage = MessageProto.Message.parseFrom(bytes);
            
            // 创建并返回Java的Message对象
            Message message = new Message();
            message.setName(protoMessage.hasName() ? protoMessage.getName() : null);
            message.setId(protoMessage.hasId() ? protoMessage.getId() : null);
            message.setClazz(protoMessage.hasClazz() ? protoMessage.getClazz() : null);
            message.setCompulsory(protoMessage.getCompulsory());
            
            logger.fine("Protobuf字节数组解析成功");
            return message;
        } catch (InvalidProtocolBufferException e) {
            logger.log(Level.SEVERE, "Protobuf字节数组解析失败", e);
            throw new IOException("解析Protobuf字节数组失败: " + e.getMessage(), e);
        }
    }

    /**
     * 将压缩的Protobuf字节数组解压并解析为Java的Message对象
     * @param compressedBytes 压缩的Protobuf字节数组
     * @return 解析后的Java Message对象
     * @throws IOException 当解析失败时抛出
     * @throws IllegalArgumentException 如果compressedBytes为null或空
     */
    public static Message decodeMessageFromCompressed(byte[] compressedBytes) throws IOException {
        if (compressedBytes == null || compressedBytes.length == 0) {
            throw new IllegalArgumentException("压缩字节数组不能为空");
        }
        
        try {
            // 解压数据
            ByteArrayInputStream bais = new ByteArrayInputStream(compressedBytes);
            Inflater inflater = new Inflater();
            InflaterInputStream iis = new InflaterInputStream(bais, inflater);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = iis.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesRead);
            }
            
            iis.close();
            byte[] protobufBytes = baos.toByteArray();
            
            logger.fine("Protobuf字节数组解压成功，原始大小: " + compressedBytes.length + ", 解压后大小: " + protobufBytes.length);
            
            // 解析解压后的数据
            return decodeMessage(protobufBytes);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "解压并解析Protobuf字节数组失败", e);
            throw new IOException("解压并解析Protobuf字节数组失败: " + e.getMessage(), e);
        }
    }

    /**
     * 批量序列化多个Message对象
     * @param messages Message对象列表
     * @return 序列化后的字节数组列表
     * @throws IllegalArgumentException 如果messages为null
     */
    public static List<byte[]> encodeMessages(List<Message> messages) {
        if (messages == null) {
            throw new IllegalArgumentException("Messages列表不能为空");
        }
        
        List<byte[]> resultList = new ArrayList<>(messages.size());
        for (Message message : messages) {
            resultList.add(encodeMessage(message));
        }
        
        logger.fine("批量序列化完成，共处理 " + messages.size() + " 个Message对象");
        return resultList;
    }

    /**
     * 批量反序列化多个Protobuf字节数组
     * @param bytesList Protobuf字节数组列表
     * @return 解析后的Message对象列表
     * @throws IOException 当解析失败时抛出
     * @throws IllegalArgumentException 如果bytesList为null
     */
    public static List<Message> decodeMessages(List<byte[]> bytesList) throws IOException {
        if (bytesList == null) {
            throw new IllegalArgumentException("字节数组列表不能为空");
        }
        
        List<Message> resultList = new ArrayList<>(bytesList.size());
        for (byte[] bytes : bytesList) {
            resultList.add(decodeMessage(bytes));
        }
        
        logger.fine("批量反序列化完成，共处理 " + bytesList.size() + " 个字节数组");
        return resultList;
    }

    /**
     * 验证Protobuf字节数组是否有效
     * @param bytes 要验证的字节数组
     * @return 如果字节数组有效返回true，否则返回false
     */
    public static boolean isValidProtobuf(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return false;
        }
        
        try {
            MessageProto.Message.parseFrom(bytes);
            return true;
        } catch (InvalidProtocolBufferException e) {
            logger.fine("Protobuf字节数组无效: " + e.getMessage());
            return false;
        }
    }
}